#include "client.h"

//===============================================================
// Initializes a client connection with the game server.
//===============================================================
CClient::CClient(const char *szHostAddr, u_short nPort)
	:	m_nBufferOutPos(0), 
		m_nBufferInPos(0)
{
	WSAStartup(MAKEWORD(2, 2), &m_wsaData);
	
	FD_ZERO(&m_fdRead);
	FD_ZERO(&m_fdWrite);

	ZeroMemory(&m_saAddr, sizeof(SOCKADDR_IN));
	m_saAddr.sin_family      = AF_INET;
	m_saAddr.sin_port        = htons(nPort);
	m_saAddr.sin_addr.s_addr = inet_addr(szHostAddr);

	m_nSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (connect(m_nSock, (SOCKADDR *)&m_saAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
	{

		printf("Failed to connect to the server (ERR %d)\n", WSAGetLastError());
		return;
	}

	u_long nNonBlocking = 1;
	ioctlsocket(m_nSock, FIONBIO, &nNonBlocking);

	printf("Succesfully connected to the server.\n");

	CPacket packet(100);
	packet.Write("IDENTSTR");
	Send(PMC_IDENTIFY, &packet);

}

//===============================================================
// Closes the connection with the game server.
//===============================================================
CClient::~CClient()
{
	closesocket(m_nSock);
	WSACleanup();
}

//===============================================================
// Processing incoming and outgoing data.
//===============================================================
void CClient::Update()
{
	FD_SET(m_nSock, &m_fdRead);
	FD_SET(m_nSock, &m_fdWrite);

	select(m_nSock + 1, &m_fdRead, &m_fdWrite, NULL, NULL);
	if (FD_ISSET(m_nSock, &m_fdRead))
	{
		if (!Receive())
			return;
	}

	if (m_nBufferOutPos > 0)
	{
		if (FD_ISSET(m_nSock, &m_fdWrite))
		{
			if (!Send())
				return;
		}
	}
}

//===============================================================
// Sends data to the server.
//===============================================================
bool CClient::Send()
{
	if (m_nBufferOutPos == 0)
		return false;

	if (send(m_nSock, m_pBufferOut, m_nBufferOutPos, 0) == SOCKET_ERROR)
	{
		int nErr = WSAGetLastError();
		switch (nErr) 
		{
			case WSAENETDOWN:
            case WSAENETRESET:
            case WSAENOTCONN:
            case WSAEHOSTUNREACH:
            case WSAECONNABORTED:
            case WSAECONNRESET:
            case WSAETIMEDOUT:
            case WSAESHUTDOWN:
				/* If one of the cases above occurs the connection has been permanently lost. */
				//Terminate(pClient); 
				return false;
		}
	}

	printf("Send %d bytes to server.\n", m_nBufferOutPos);
	m_nBufferOutPos = 0;
	return true;
}

//===============================================================
// Receives data from the server.
//===============================================================
bool CClient::Receive()
{
	int nRecv = recv(m_nSock, m_pBufferIn + m_nBufferInPos, (BUFFER_SIZE - m_nBufferInPos), 0);
	if (nRecv == SOCKET_ERROR)
	{
		int nErr = WSAGetLastError();
		switch (nErr)
		{
			case WSAENETDOWN:
			case WSAENETRESET:
			case WSAENOTCONN:
			case WSAEHOSTUNREACH:
			case WSAECONNABORTED:
			case WSAECONNRESET:
			case WSAETIMEDOUT:
			case WSAESHUTDOWN:
				/* If one of the cases above occurs the connection has been permanently lost. */
				//Terminate(pClient);
				return false;

			default:
				return true;
		}
	}

	/* If we receive 0, the connection has been closed. */
	if (nRecv == 0)
	{
		//Terminate(pClient);
		return false;
	}
	else
	{
		m_nBufferInPos += nRecv;
		printf("Received %d bytes.\n", nRecv);
	}
	return true;
}

//===============================================================
// Sends the specified packet to the server.
//===============================================================
void CClient::Send(u_short nMsg, CPacket *pPacket)
{
	if (!pPacket)
		return;

	/* Write packet size to the buffer. */
	u_int nLen = pPacket->GetContentSize() + 2;
	m_pBufferOut[m_nBufferOutPos] = ((nLen & 0xFF00) >> 8);
	m_pBufferOut[m_nBufferOutPos + 1] = (nLen & 0xFF);

	/* Write the packet to the outgoing data buffer. */
	m_pBufferOut[m_nBufferOutPos + 2] = ((nMsg & 0xFF00) >> 8);
	m_pBufferOut[m_nBufferOutPos + 3] = (nMsg & 0xFF);
	memcpy(m_pBufferOut + m_nBufferOutPos + 4, pPacket->GetData(), nLen);
	m_nBufferOutPos += nLen + 2;
}
